package ULT;

import android.graphics.Point;

import com.fitsoftwareprocess.mobimap.dto.Coordinate;
import com.fitsoftwareprocess.mobimap.dto.Size;

public class LocateConvert {

	
static double MinLatitude = -85.05112878;
static double MaxLatitude = 85.05112878;
static double MinLongitude = -177;
static double MaxLongitude = 177;
    static Size tileDefaultSize = new Size(256, 256);

    private static double Clip(double n, double minValue, double maxValue)
    {
        return Math.min(Math.max(n, minValue), maxValue);
    }

    private static Size GetTileMatrixSizePixel(int zoom)
    {
        Size s = GetTileMatrixSizeXY(zoom);
        return new Size(s.Width * tileDefaultSize.Width, s.Height * tileDefaultSize.Height);
    }

    private static Size GetTileMatrixMaxXY(int zoom)
    {
        int xy = (1 << zoom);
        return new Size(xy - 1, xy - 1);
    }

    private static Size GetTileMatrixMinXY(int zoom)
    {
        return new Size(0, 0);
    }

    private static Size GetTileMatrixSizeXY(int zoom)
    {
        Size sMin = GetTileMatrixMinXY(zoom);
        Size sMax = GetTileMatrixMaxXY(zoom);

        return new Size(sMax.Width - sMin.Width + 1, sMax.Height - sMin.Height + 1);
    }

    public static Point ToPoint(Coordinate geoCoordinate, int zoom)
    {
        Point ret= null;
        geoCoordinate._latitude = Clip(geoCoordinate._latitude, MinLatitude, MaxLatitude);
        geoCoordinate._longitude = Clip(geoCoordinate._longitude, MinLongitude, MaxLongitude);

        double x = (geoCoordinate._longitude+ 180) / 360;
        double sinLatitude = Math.sin(geoCoordinate._latitude * Math.PI / 180);
        double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);

        Size s = GetTileMatrixSizePixel(zoom);
        int mapSizeX = s.Width;
        int mapSizeY = s.Height;

        ret.x = (int)Clip(x * mapSizeX + 0.5, 0, mapSizeX - 1);
        ret.y = (int)Clip(y * mapSizeY + 0.5, 0, mapSizeY - 1);

        return ret;
    }

    public static Point ToPoint(double longitude, double latitude, int zoom)
    {
        Point ret = null;
        latitude = Clip(latitude, MinLatitude, MaxLatitude);
        longitude = Clip(longitude, MinLongitude, MaxLongitude);

        double x = (longitude + 180) / 360;
        double sinLatitude = Math.sin(latitude * Math.PI / 180);
        double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);

        Size s = GetTileMatrixSizePixel(zoom);
        int mapSizeX = s.Width;
        int mapSizeY = s.Height;

        ret.x = (int)Clip(x * mapSizeX + 0.5, 0, mapSizeX - 1);
        ret.y = (int)Clip(y * mapSizeY + 0.5, 0, mapSizeY - 1);

        return ret;

    }

    public static Coordinate ToGeographicCoordinate(Point point, int zoom)
    {
        Coordinate ret = new Coordinate();
        Size s = GetTileMatrixSizePixel(zoom);
        double mapSizeX = s.Width;
        double mapSizeY = s.Height;
        double xx = (Clip(point.x, 0, mapSizeX - 1) / mapSizeX) - 0.5;
        double yy = 0.5 - (Clip(point.y, 0, mapSizeY - 1) / mapSizeY);
        ret._latitude = 90 - 360 * Math.atan(Math.exp(-yy * 2 * Math.PI)) / Math.PI;
        ret._longitude = 360 * xx;
        return ret;
    }

    public static Coordinate ToGeographicCoordinate(int X, int Y, int zoom)
    {
        Coordinate ret = new Coordinate();

        Size s = GetTileMatrixSizePixel(zoom);
        double mapSizeX = s.Width;
        double mapSizeY = s.Height;

        double xx = (Clip(X, 0, mapSizeX - 1) / mapSizeX) - 0.5;
        double yy = 0.5 - (Clip(Y, 0, mapSizeY - 1) / mapSizeY);

        ret._latitude = 90 - 360 * Math.atan(Math.exp(-yy * 2 * Math.PI)) / Math.PI;
        ret._longitude = 360 * xx;
        return ret;
    }

    public static Point ToTile(double longitude, double latitude, int zoom)
    {
        Point result = ToPoint(longitude, latitude, zoom);
        result.x /= 256;
        result.y /= 256;
        return result;
    }

    public static Point ToTile(Coordinate coordiante, int zoom)
    {
        Point result = ToPoint(coordiante, zoom);
        result.x /= 256;
        result.y /= 256;
        return result;
    }

    public static Point ToTile(Point globalPoint, int zoom)
    {
        Coordinate coordinate = ToGeographicCoordinate(globalPoint, zoom);
        return ToTile(coordinate, zoom);
    }

	
}
